import requests
import re
import random
from frame_work.excel import get_all_data
from frame_work.util import (
    get_sql_info,
    check_tid,
    change_user_account_status,
    bind_tb,
    assert_result_dict,
    get_str
)
from frame_work.logger import Logger
from frame_work.login import PcLogin, AppLogin
from frame_work import menu_list
from multiprocessing import cpu_count, Pool
from frame_work.setting import *
from frame_work.yaml_file import YAML

logger = Logger(__name__).get_logger()


class Apply(object):
    # 定义申请成功数量初始值
    init_sum = 0

    def __init__(self, tid):
        self.tid = tid
        self.yaml = YAML(os.path.join(base_Dir, 'data', 'data.yaml'))

    @staticmethod
    def get_user_data(nums):
        """
        批量读取/data/buyer_data.xlsx试客账户，达到申请数量目的
        :param nums:
        :return:
        """
        data = get_all_data(1)
        # 打乱user_data里边的数据
        # random.shuffle(data)
        user_data = []
        for uname in data:
            if nums == len(user_data):
                break
            # 如果用户状态不对，改为正常
            # account_status = change_user_account_status(uname)
            # 没绑淘宝就开始绑订
            # tb_status = bind_tb(uname)
            # if account_status and tb_status:
            # if account_status:
            #     user_data.append(uname)
            user_data.append(uname)
            continue
        return user_data

    @staticmethod
    def sum(res):
        # 批量申请累计数量 res为异步回调结果
        if res:
            Apply.init_sum += 1
        return Apply.init_sum

    @staticmethod
    def multi_async_apply(f, *args, **kwargs):
        """
        多进程异步执行批量申请
        :param f: 目标待执行函数
        :param args:
        :param kwargs:
        :return:
        """
        p = Pool(cpu_count())
        # 初始赋值
        Apply.init_sum = 0
        for uname in args:
            # 多进程异步执行PC/APP申请申请
            res = p.apply_async(func=f, args=(uname,), callback=Apply.sum)
        # 不在接收任何进程
        p.close()
        # 等待所有子进程结束
        p.join()
        if kwargs.get('num') == Apply.init_sum:
            logger.info("达到申请成功的数量:%s" % Apply.init_sum)
        else:
            logger.info(
                "还差: %s个未申请成功,可能是账户问题,请单个执行！" %
                (kwargs.get('num') - Apply.init_sum))


class PcApply(Apply):

    # PC活动申请
    def __init__(self, tid):
        super().__init__(tid)

    @staticmethod
    def get_session(uname):
        # 返回登录session
        # 如果用户状态不对，改为正常
        # change_user_account_status(uname)
        # 没绑淘宝就开始绑订
        bind_tb(uname)
        login = PcLogin(uname)
        login.pc_login()
        return login.get_session()

    def get_cache_key(self):
        """
        该方法目的就是获取cache_key值,因为申请试用需要带这个参数
        :return:
        """
        # 获取cache_key
        # url = 'http://platinum' + '.' + self.domain + '.com/data/' + str(self.tid) + '/'
        yaml_data = self.yaml.get_data('detail_cache_key')
        getkey = self.session.get(yaml_data.get(
            'url') + '/' + str(self.tid) + '/').text
        try:
            cache_key = re.findall(r'"key":"(.*?)"', getkey)[0]
            logger.debug('获取缓存Key值 => %s...' % cache_key)
        except (IndexError, KeyError) as e:
            logger.error('获取cache_key失败，请检查response中该key:value键值是否改变了')
            return False
        else:
            return cache_key

    def apply(self, uname):
        """
        PC申请精品试用
        :param uname:
        :return:
        """
        self.session = PcApply.get_session(uname)
        yaml_data = self.yaml.get_data('pc_apply')
        cache_key = self.get_cache_key()
        yaml_data.get('data').update({'cache_key': cache_key})
        apply_url = yaml_data.get('url') + '/' + \
            str(self.tid) + '?callback=trysapply'
        logger.debug('开始申请精品试用资格')
        response = self.session.post(
            apply_url,
            data=yaml_data.get('data'),
            headers=yaml_data.get('header')).text
        try:
            res_str = get_str(response, 'trysapply(', ')')
        except Exception as e:
            logger.debug('响应值处理失败:%s 响应内容：%s' % (e, response))
            return False
        else:
            assert_result = assert_result_dict(
                res_str, uname + '申请tid:' + str(self.tid) + '精品试用活动')
            logger.debug('申请结束')
            return assert_result


class AppApply(Apply):

    # APP活动申请
    def __init__(self, tid):
        Apply.__init__(self, tid)

    @staticmethod
    def get_session(uname):
        # 返回登录session
        login = AppLogin(uname)
        sign = login.appget_sign()
        return sign

    def app_apply(self, uname):
        """
        app端申请精品
        :param uname:
        :param type:
        :return:
        """
        statement = """select uid from sk_user where uname = %s"""
        params = (uname,)
        value = get_sql_info(statement, params, meta={
            "info": "查询uid"
        })
        sign = AppApply.get_session(uname)
        if sign:
            yaml_data = self.yaml.get_data('app_apply')
            yaml_data.get('data').update({'uid': value[0].get("uid"),
                                          'tid': self.tid,
                                          'sign': sign
                                          })
            logger.debug('开始app申请精品试用资格')
            response = requests.post(
                url=yaml_data.get('url'),
                data=yaml_data.get('data'),
                headers=yaml_data.get('header')).text
            status = assert_result_dict(
                response, uname + '申请tid:' + str(self.tid) + '精品试用活动')
            return status
        else:
            logger.debug('APP登录失败')


def main():
    while True:
        # 选择功能菜单
        menu_list.quality_apply_menu()
        # 选择
        choise = input("请输入您的选择: ")
        if choise in ('q', 'Q'):
            break
        try:
            tid = int(input(u'请输入活动tid: '))
            status = check_tid(tid)
            if not status:
                raise Exception("活动tid不存在try表，请核实后在重新输入")
        except Exception as e:
            logger.error("reszon => %s" % e)
        else:
            if choise == '1':
                # 统一PC
                uname = input('请输入您指定的试客账户名: ')
                apply_obj = PcApply(tid)
                apply_obj.apply(uname)
            elif choise == '2':
                # type=1为app直接申请
                # app端申请，需要在app端做登录以获取申请接口参数sign值
                uname = input('请输入您指定的试客账户名: ')
                app_apply_obj = AppApply(tid)
                app_apply_obj.app_apply(uname)
            elif choise == '3':
                # 批量PC申请
                num = int(input(u'请输入批量申请数量: '))
                apply_obj = PcApply(tid)
                user_datas = apply_obj.get_user_data(num)
                apply_obj.multi_async_apply(
                    apply_obj.apply, *user_datas, num=num)
            elif choise == '4':
                # 批量app申请
                num = int(input(u'请输入批量申请数量: '))
                app_apply_obj = AppApply(tid)
                user_datas = app_apply_obj.get_user_data(num)
                app_apply_obj.multi_async_apply(
                    app_apply_obj.app_apply, *user_datas, num=num)
            else:
                logger.info("没有对应的选项,请按选项输入...")
                break


if __name__ == '__main__':
    main()
